package hu.bme.mit.rifl.business.base;

import hu.bme.mit.rifl.datamodel.Order;
import hu.bme.mit.rifl.gui.WFElementGUI;

import java.util.ArrayList;
import java.util.List;

/**
 * Base class for the worker nodes of the workflow. Implements the Runnable
 * interface and defines a common run method for the inheriting classes. Also
 * defines a default pull-return style interaction with the central coordinator
 * node.
 */
public abstract class WFElement implements Runnable {

	// The current Order work item.
	protected Order order;
	// GUI
	protected WFElementGUI gui;
	// Collections of queues for inputs and outputs.
	protected List<RiflOrderQueue> inputs;
	protected List<RiflOrderQueue> outputs;

	/**
	 * Constructor with a reference to the central coordinator node.
	 * 
	 * @param coordinator
	 *            a reference to the central coordinator node.
	 * @param title
	 *            title for the Swing window
	 */
	public WFElement(String title) {
		this.gui = new WFElementGUI(title);
		this.gui.setVisible(true);
		inputs = new ArrayList<RiflOrderQueue>();
		outputs = new ArrayList<RiflOrderQueue>();
	}

	/**
	 * Overridden method of the Runnable interface.
	 */
	@Override
	public void run() {
		while (!gui.isClosed()) {
			try {
				pull();
				if (this.order != null) {
					gui.called();
					gui.log("\n### NEW ORDER ###\n");

					while (!gui.isButtonClicked()) {
						Thread.sleep(100);
					}
					process();

					LogResult();
					finish();
				}
				Thread.sleep(100);
			} catch (InterruptedException e) {
				System.out.println(e.getMessage());
			}
		}

		gui.dispose();

		for (RiflOrderQueue queue : inputs) {
			queue.close();
		}
		for (RiflOrderQueue queue : outputs) {
			queue.close();
		}
	}

	/**
	 * The actual business logic executed in the run method. Must be overridden
	 * by every inheriting node.
	 */
	public abstract void process();

	/**
	 * Getter for the current work item.
	 * 
	 * @return the current work item
	 */
	public Order getOrder() {
		return order;
	}

	/**
	 * Pulls the next available work item from the input queue of the node
	 * stored in the central coordinator.
	 */
	public void pull() {
		for (RiflOrderQueue queue : inputs) {
			this.order = queue.get();
			if (this.order != null)
				return;
		}
	}

	/**
	 * Returns the processed work item to the central coordinator.
	 */
	protected void finish() {
		outputs.get(0).put(this.order);
		this.order = null;
	}

	/**
	 * A simplistic log method. The log message is displayed on the console and
	 * in the monitor windows.
	 */
	protected void LogResult() {
		String log = this.getClass().getSimpleName() + ":Order with ID "
				+ this.order.getOrderID() + ": new state: "
				+ this.order.getState() + ".";

		System.out.println(log);
		gui.log(log);
	}
}